﻿// SEE THIS POST for full details of what this does
//http://shazwazza.com/post/Developing-a-plugin-framework-in-ASPNET-with-medium-trust.aspx

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web.Compilation;
using Actya.Core.Infrastructure.Logging;
using Actya.Web.Infrastructure;
using WebActivator;

[assembly: PreApplicationStartMethod(typeof(PluginManager), "Initialize")]
namespace Actya.Web.Infrastructure
{
	/// <summary>
	/// Sets the application up for the plugin referencing
	/// </summary>
	public class PluginManager
	{
		private readonly static object Locker = new object();
		private static readonly ILogger Logger = LogManager.GetLogger(typeof (PluginManager));

		/// <summary>
		/// Returns the file path of the shadow copy folder.
		/// </summary>
		public static string ShadowCopyDirectory { get; private set; }

		public static void Initialize()
		{
			lock (Locker)
			{
				var host = CmsHost.GetInstance();
				var pluginsDirectory = host.PhysicalPluginsDirectory;

				//var shadowCopyDirectory = new DirectoryInfo(Path.Combine(pluginsDirectory, "bin"));
				//try
				//{
				//    if (!shadowCopyDirectory.Exists)
				//    {
				//        shadowCopyDirectory.Create();
				//    }
				//    else
				//    {
				//        foreach (var fi in shadowCopyDirectory.EnumerateFiles().ToArray())
				//        {
				//            fi.Delete();
				//        }
				//    }
				//}
				//catch (UnauthorizedAccessException ex)
				//{
				//    throw new UnauthorizedAccessException(
				//        "Unable to initialize shadow copy directory for plugins. Make sure that the ~/CmsContent directory is writable.",
				//        ex);
				//}

				var shadowCopyDirectory = new DirectoryInfo(AppDomain.CurrentDomain.DynamicDirectory);

				// Copy plugins to shadow copy location and load em.
				var pluginAssemblies = Directory.EnumerateFiles(pluginsDirectory, "*.dll", SearchOption.AllDirectories).ToArray();

				if (pluginAssemblies.Any())
				{
					foreach (var pluginAssemblyPath in pluginAssemblies)
					{
						var destinationPath = Path.Combine(shadowCopyDirectory.FullName, Path.GetFileName(pluginAssemblyPath));
						try
						{
							File.Copy(pluginAssemblyPath, destinationPath, true);
						}
						catch (IOException)
						{
							Logger.Info("Creating shadow copy failed. Trying to rename the old file.");
							try
							{
								var oldFile = destinationPath + Guid.NewGuid().ToString("N") + ".old";
								File.Move(destinationPath, oldFile);
							}
							catch (IOException)
							{
								Logger.Error("{0} rename failed, cannot initialize plugin", destinationPath);
								throw;
							}
							// ok, we've made it this far, now retry the shadow copy
							File.Copy(pluginAssemblyPath, destinationPath, true);
						}
						var shadowCopiedAssembly = Assembly.Load(AssemblyName.GetAssemblyName(destinationPath));
						BuildManager.AddReferencedAssembly(shadowCopiedAssembly);
					}
					ShadowCopyDirectory = shadowCopyDirectory.FullName;
				}
			}
		}
	}
}
